//
//  NSObject+KLSupportRACKVO.m
//  yangtao
//
//  Created by Tommy on 14/10/28.
//  Copyright (c) 2014年 com.taobao. All rights reserved.
//

#import "ReactiveCocoa.h"
#import "NSObject+KLSupportRACKVO.h"
#import "RACSignal+Operations.h"
#import <objc/runtime.h>


@interface KLRACSubscriptingAssignmentTrampoline ()

// The object to bind to.
@property (nonatomic, strong, readonly) id target;

// A value to use when `nil` is sent on the bound signal.
@property (nonatomic, strong, readonly) id nilValue;

@property (nonatomic, strong) RACDisposable *dispose;

@end

@implementation KLRACSubscriptingAssignmentTrampoline

- (id)initWithTarget:(id)target nilValue:(id)nilValue {
    // This is often a programmer error, but this prevents crashes if the target
    // object has unexpectedly deallocated.
    if (target == nil) return nil;
    
    self = [super init];
    if (self == nil) return nil;
    
    _target = target;
    _nilValue = nilValue;
    
    return self;
}

- (void)setObject:(RACSignal *)signal forKeyedSubscript:(NSString *)keyPath {
    RACDisposable* dispose = [self.target klDisposable:keyPath];
    [dispose dispose];
    
    if(signal){
        _dispose = [signal setKeyPath:keyPath onObject:self.target nilValue:self.nilValue];
        [self.target setKLDisposable:_dispose forKeyPath:keyPath];
    }else{
        [self.target removeKLDisposable:keyPath];
    }
}



@end

#define KLNSObjectDisposeable   "__KLNSObjectDisposeable__"

@implementation NSObject (KLSupportRACKVO)

- (void)setKLDisposable:(RACDisposable*)disposable forKeyPath:(NSString *)keyPath{
    if([disposable isKindOfClass:[RACDisposable class]]){
        NSMutableDictionary *bindings;
        @synchronized (self) {
            bindings = objc_getAssociatedObject(self, KLNSObjectDisposeable);
            if (bindings == nil) {
                bindings = [NSMutableDictionary dictionary];
                objc_setAssociatedObject(self, KLNSObjectDisposeable, bindings, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
            }
        }
        @synchronized (bindings) {
            bindings[keyPath] = disposable;
        }
    }
}

- (RACDisposable*)klDisposable:(NSString*)keyPath{
    
    NSMutableDictionary *bindings;
    @synchronized (self) {
        bindings = objc_getAssociatedObject(self, KLNSObjectDisposeable);
    }
    RACDisposable* dispose = nil;
    @synchronized (bindings) {
        dispose = bindings[keyPath];
    }
    return dispose;
}

- (void)removeKLDisposable:(NSString*)keyPath{
    NSMutableDictionary *bindings;
    @synchronized (self) {
        bindings = objc_getAssociatedObject(self, KLNSObjectDisposeable);
    }
    @synchronized (bindings) {
        [bindings removeObjectForKey:keyPath];
    }
}

@end
